package cn.edu.xjtu.android.emoji_warfare_android.engine.worker;

import android.util.Log;
import cn.edu.xjtu.android.emoji_warfare_android.engine.BaseEngine;
import cn.edu.xjtu.android.emoji_warfare_android.util.Gap;

/**
 * BaseWorker<br>
 * 工作者，是一个循环器<br>
 * 针对某一种事件，带有启动/恢复、暂停/停止功能的循环<br>
 * 例如图像渲染引擎是一个BaseWorker，其循环内容为反复渲染。<br>
 * 物理引擎有两个BaseWorker，一个为移动对象，一个为碰撞检测，等等。
 * 
 * @author bill
 *
 */
public abstract class BaseWorker {
    /**
     * 引擎
     */
    protected BaseEngine engine;
    /**
     * 执行完一次循环以后的回调函数
     */
    private Runnable finishCallback;
    /**
     * 线程循环核心
     */
    private Core core;

    Gap g;

    private boolean debug = false;

    /**
     * 构建一个Woker，包括设置TAG，创建新线程
     * 
     * @param engine
     *            引擎
     * @param interval
     *            循环间隔
     */
    public BaseWorker(BaseEngine engine, long interval) {
        if (engine == null) {
            throw new IllegalArgumentException("BaseEngine can't be null");
        }
        if (interval <= 0) {
            throw new IllegalArgumentException("The interval must greater than zero");
        }
        this.engine = engine;
        core = new Core(this);
        core.interval = interval;
        core.start();
        if (debug) {
            Log.d("Worker", "Created");
            g = new Gap(this.getClass().getName());
            g.mstart();
        }
    }

    /**
     * 一轮事件处理
     */
    /* package */ void round() {
        run();
        if (finishCallback != null) {
            finishCallback.run();
        }
        if (debug) {
            g.mlog();
        }
    }

    /**
     * 每一次循环中执行的主任务
     */
    public abstract void run();

    /**
     * 返回该线程的运行状态
     * 
     * @return 该线程是否在运行
     */
    public boolean isRunning() {
        return core.running;
    }

    /**
     * 启动/恢复消息循环
     */
    public void resume() {
        core.running = true;
        core.interrupt();
    }

    /**
     * 停止/暂停消息循环
     */
    public void pause() {
        core.running = false;
    }

    public void stop() {
        core.isStop = true;
    }

    /**
     * 设置循环之间的时间间隔，单位为毫秒
     * 
     * @param interval
     *            时间间隔
     */
    public void setInterval(long interval) {
        core.interval = interval;
    }

    /**
     * 设置执行完一次循环以后的回调函数
     * 
     * @param c
     *            回调
     */
    public void setFinishCallback(Runnable c) {
        this.finishCallback = c;
    }

    public String getError() {
        return core.error;
    }

    /**
     * 核心循环线程
     * 
     * @author bill
     *
     */
    private static class Core extends Thread {
        /**
         * 两次事件时间间隔
         */
        public long interval;
        /**
         * 是否出在运行状态
         */
        public boolean running;

        public boolean isStop;
        /**
         * 上一次执行时间
         */
        private long last;
        /**
         * 外部类Woker引用
         */
        private BaseWorker w;

        private String error;

        /**
         * 构造一个循环线程
         * 
         * @param w
         *            外部类引用
         */
        public Core(BaseWorker w) {
            this.w = w;
            running = false;
            error = "";
            isStop = false;
        }

        /**
         * 线程循环
         */
        @Override
        public void run() {
            last = w.engine.clock();
            long now;
            for (;;) {
                if (isStop) {
                    break;
                }

                // 获取当前时间并等待若干毫秒
                now = w.engine.clock();
                if (now - last < interval) {
                    // 这里有必要多次睡眠一毫秒而不是直接睡眠interval
                    // 因为有些线程任务繁重(比如Render), 实际运行时间较长
                    // 如果直接睡眠interval会造成时间不准
                    // 通过这种方式可以较为精确地实现睡眠到下一个毫秒倍数位置
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                    }
                    continue;
                }

                // 记录run的运行开始时间
                last = now;
                try {
                    w.round();

                    // 线程暂停
                    if (!running) {
                        synchronized (this) {
                            this.wait();
                        }
                    }
                } catch (InterruptedException e) {

                    // 线程恢复
                    continue;
                } catch (Exception e) {

                    // 线程崩溃
                    running = false;
                    StringBuilder sb = new StringBuilder();
                    StackTraceElement[] ste = e.getStackTrace();
                    sb.append("\n");
                    sb.append(e.toString());
                    for (StackTraceElement st : ste) {
                        sb.append("\nat ");
                        sb.append(st.toString());
                    }
                    error = sb.toString();
                    Log.d("Worker", "Worker thread quiting at :" + error);
                    break;
                }
            }
        }

    }
}